' Copyright (c) Microsoft Corporation.  All rights reserved.
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Data

Namespace EdmMetadataHelpersVB
    ''' <summary>
    ''' Implements an IEnumerable(Of IDataRecord) over an IDataReader
    ''' which allows you to ForEach over a datareader.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class DataReaderEnumerable
        Implements IEnumerable(Of IDataRecord), IEnumerable

        Public Sub New(ByVal reader As IDataReader)
            Me._reader = reader
        End Sub
        ''' <summary>
        ''' Get an Enumerator
        ''' </summary>
        ''' <remarks>
        ''' Since a DataReader can only be enumerated once, this method only works 
        ''' once per Enumerable
        ''' </remarks>
        Public Function GetEnumerator() As IEnumerator(Of IDataRecord) Implements IEnumerable(Of System.Data.IDataRecord).GetEnumerator
            If Me._enumerated Then
                Throw New InvalidOperationException("You can only enumerate a DataReader once")
            End If
            Me._enumerated = True
            Return New DataReaderEnumerator(Me._reader)
        End Function

        Private Function GetEnumeratorNonGeneric() As IEnumerator Implements IEnumerable.GetEnumerator
            Return Me.GetEnumerator
        End Function

        ' Fields
        Private _enumerated As Boolean = False
        Private _reader As IDataReader

        ''' <summary>
        ''' An implementation of a Enumerator over the top of an IDataReader 
        ''' </summary>
        ''' <remarks></remarks>
        Private Class DataReaderEnumerator
            Implements IEnumerator(Of IDataRecord), IDisposable, IEnumerator
            ' Methods
            Public Sub New(ByVal reader As IDataReader)
                Me._reader = reader
            End Sub

            Public Sub Dispose() Implements IDisposable.Dispose
                If Not Me._reader.IsClosed Then
                    Me._reader.Close()
                End If
            End Sub

            Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
                Return Me._reader.Read
            End Function

            Public Sub Reset() Implements IEnumerator.Reset
                Throw New NotImplementedException("Reset is not supported")
            End Sub
            ''' <summary>
            ''' Since IDataReader also implements IDataRecord we simple return it.
            ''' </summary>
            ''' <remarks>
            ''' The assumption is that callers don't cast back to a DataReader
            ''' and muck around with the internal state
            ''' 
            ''' A nice extension would be to make that impossible by wrapping the Reader
            ''' in a class that simply implements IDataRecord and forwards all calls to the 
            ''' Reader.
            ''' </remarks>
            Public ReadOnly Property Current() As IDataRecord Implements IEnumerator(Of System.Data.IDataRecord).Current
                Get
                    Return Me._reader
                End Get
            End Property


            ' Properties
            Private ReadOnly Property CurrentNonGeneric() As Object Implements IEnumerator.Current
                Get
                    Return Me._reader
                End Get
            End Property


            ' Fields
            Private _reader As IDataReader
        End Class
    End Class
End Namespace

